 /*******************************************************************************
  * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.part;

 import java.util.Collections ;
 import java.util.HashMap ;
 import java.util.Map ;

 import org.eclipse.core.commands.common.EventManager;
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.IConfigurationElement;
 import org.eclipse.core.runtime.IExecutableExtension;
 import org.eclipse.core.runtime.ListenerList;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;
 import org.eclipse.jface.window.Window;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.ui.IPropertyListener;
 import org.eclipse.ui.ISharedImages;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.IWorkbenchPart3;
 import org.eclipse.ui.IWorkbenchPartConstants;
 import org.eclipse.ui.IWorkbenchPartSite;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.internal.WorkbenchMessages;
 import org.eclipse.ui.internal.WorkbenchPlugin;
 import org.eclipse.ui.internal.util.Util;
 import org.eclipse.ui.plugin.AbstractUIPlugin;

 import com.ibm.icu.text.MessageFormat;

 /**
  * Abstract base implementation of all workbench parts.
  * <p>
  * This class is not intended to be subclassed by clients outside this
  * package; clients should instead subclass <code>ViewPart</code> or
  * <code>EditorPart</code>.
  * </p>
  *
  * @see org.eclipse.ui.part.ViewPart
  * @see org.eclipse.ui.part.EditorPart
  */
 public abstract class WorkbenchPart extends EventManager implements
         IWorkbenchPart3, IExecutableExtension, IWorkbenchPartOrientation {
     private String title = ""; //$NON-NLS-1$

     private ImageDescriptor imageDescriptor;

     private Image titleImage;

     private String toolTip = ""; //$NON-NLS-1$

     private IConfigurationElement configElement;

     private IWorkbenchPartSite partSite;

     private String partName = ""; //$NON-NLS-1$

     private String contentDescription = ""; //$NON-NLS-1$

     private ListenerList partChangeListeners = new ListenerList();

     /**
      * Creates a new workbench part.
      */
     protected WorkbenchPart() {
         super();
     }

     /* (non-Javadoc)
      * Method declared on IWorkbenchPart.
      */
     public void addPropertyListener(IPropertyListener l) {
         addListenerObject(l);
     }

     /* (non-Javadoc)
      * Creates the SWT controls for this workbench part.
      * <p>
      * Subclasses must implement this method. For a detailed description of the
      * requirements see <code>IWorkbenchPart</code>
      * </p>
      *
      * @param parent the parent control
      * @see IWorkbenchPart
      */
     public abstract void createPartControl(Composite parent);

     /**
      * The <code>WorkbenchPart</code> implementation of this
      * <code>IWorkbenchPart</code> method disposes the title image
      * loaded by <code>setInitializationData</code>. Subclasses may extend.
      */
     public void dispose() {
         if (imageDescriptor != null) {
             JFaceResources.getResources().destroyImage(imageDescriptor);
         }

         // Clear out the property change listeners as we
 // should not be notifying anyone after the part
 // has been disposed.
 clearListeners();
         partChangeListeners.clear();
     }

     /**
      * Fires a property changed event.
      *
      * @param propertyId the id of the property that changed
      */
     protected void firePropertyChange(final int propertyId) {
         Object [] array = getListeners();
         for (int nX = 0; nX < array.length; nX++) {
             final IPropertyListener l = (IPropertyListener) array[nX];
             try {
                 l.propertyChanged(WorkbenchPart.this, propertyId);
             } catch (RuntimeException e) {
                 WorkbenchPlugin.log(e);
             }
         }
     }

     /**
      * {@inheritDoc}
      *
      * Subclasses may override this method (however, if they do so, they
      * should invoke the method on their superclass to ensure that the
      * Platform's adapter manager is consulted).
      */
     public Object getAdapter(Class adapter) {

         /**
          * This implementation of the method declared by <code>IAdaptable</code>
          * passes the request along to the platform's adapter manager; roughly
          * <code>Platform.getAdapterManager().getAdapter(this, adapter)</code>.
          */

         return Platform.getAdapterManager().getAdapter(this, adapter);
     }

     /**
      * Returns the configuration element for this part. The configuration element
      * comes from the plug-in registry entry for the extension defining this part.
      *
      * @return the configuration element for this part
      */
     protected IConfigurationElement getConfigurationElement() {
         return configElement;
     }

     /**
      * Returns the default title image.
      *
      * @return the default image
      */
     protected Image getDefaultImage() {
         return PlatformUI.getWorkbench().getSharedImages().getImage(
                 ISharedImages.IMG_DEF_VIEW);
     }

     /* (non-Javadoc)
      * Method declared on IWorkbenchPart.
      */
     public IWorkbenchPartSite getSite() {
         return partSite;
     }

     /**
      * {@inheritDoc}
      * <p>
      * It is considered bad practise to overload or extend this method.
      * Parts should set their title by calling setPartName and/or setContentDescription.
      * </p>
      */
     public String getTitle() {
         return title;
     }

     /* (non-Javadoc)
      * Method declared on IWorkbenchPart.
      */
     public Image getTitleImage() {
         if (titleImage != null) {
             return titleImage;
         }
         return getDefaultImage();
     }

     /* (non-Javadoc)
      * Gets the title tool tip text of this part.
      *
      * @return the tool tip text
      */
     public String getTitleToolTip() {
         return toolTip;
     }

     /* (non-Javadoc)
      * Method declared on IWorkbenchPart.
      */
     public void removePropertyListener(IPropertyListener l) {
         removeListenerObject(l);
     }

     /* (non-Javadoc)
      * Asks this part to take focus within the workbench.
      * <p>
      * Subclasses must implement this method. For a detailed description of the
      * requirements see <code>IWorkbenchPart</code>
      * </p>
      *
      * @see IWorkbenchPart
      */
     public abstract void setFocus();

     /**
      * {@inheritDoc}
      * The <code>WorkbenchPart</code> implementation of this
      * <code>IExecutableExtension</code> records the configuration element in
      * and internal state variable (accessible via <code>getConfigElement</code>).
      * It also loads the title image, if one is specified in the configuration element.
      * Subclasses may extend.
      *
      * Should not be called by clients. It is called by the core plugin when creating
      * this executable extension.
      */
     public void setInitializationData(IConfigurationElement cfig,
             String propertyName, Object data) {

         // Save config element.
 configElement = cfig;

         // Part name and title.
 partName = Util.safeString(cfig.getAttribute("name"));//$NON-NLS-1$;
 title = partName;

         // Icon.
 String strIcon = cfig.getAttribute("icon");//$NON-NLS-1$
 if (strIcon == null) {
             return;
         }

         imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(
                 configElement.getNamespace(), strIcon);

         if (imageDescriptor == null) {
             return;
         }

         titleImage = JFaceResources.getResources().createImageWithDefault(imageDescriptor);
     }

     /**
      * Sets the part site.
      * <p>
      * Subclasses must invoke this method from <code>IEditorPart.init</code>
      * and <code>IViewPart.init</code>.
      *
      * @param site the workbench part site
      */
     protected void setSite(IWorkbenchPartSite site) {
         checkSite(site);
         this.partSite = site;
     }

     /**
      * Checks that the given site is valid for this type of part.
      * The default implementation does nothing.
      *
      * @param site the site to check
      * @since 3.1
      */
     protected void checkSite(IWorkbenchPartSite site) {
         // do nothing
 }

     /**
      * Sets or clears the title of this part. Clients should call this method instead
      * of overriding getTitle.
      * <p>
      * This may change a title that was previously set using setPartName or setContentDescription.
      * </p>
      *
      * @deprecated new code should use setPartName and setContentDescription
      *
      * @param title the title, or <code>null</code> to clear
      */
     protected void setTitle(String title) {
         title = Util.safeString(title);

         //Do not send changes if they are the same
 if (Util.equals(this.title, title)) {
             return;
         }
         this.title = title;
         firePropertyChange(IWorkbenchPart.PROP_TITLE);
     }

     /**
      * Sets or clears the title image of this part.
      *
      * @param titleImage the title image, or <code>null</code> to clear
      */
     protected void setTitleImage(Image titleImage) {
         Assert.isTrue(titleImage == null || !titleImage.isDisposed());
         //Do not send changes if they are the same
 if (this.titleImage == titleImage) {
             return;
         }
         this.titleImage = titleImage;
         firePropertyChange(IWorkbenchPart.PROP_TITLE);
         if (imageDescriptor != null) {
             JFaceResources.getResources().destroyImage(imageDescriptor);
             imageDescriptor = null;
         }
     }

     /**
      * Sets or clears the title tool tip text of this part. Clients should
      * call this method instead of overriding <code>getTitleToolTip</code>
      *
      * @param toolTip the new tool tip text, or <code>null</code> to clear
      */
     protected void setTitleToolTip(String toolTip) {
         toolTip = Util.safeString(toolTip);
         //Do not send changes if they are the same
 if (Util.equals(this.toolTip, toolTip)) {
             return;
         }
         this.toolTip = toolTip;
         firePropertyChange(IWorkbenchPart.PROP_TITLE);
     }

     /**
      * Show that this part is busy due to a Job running that it
      * is listening to.
      * @param busy boolean to indicate that the busy state has started
      * or ended.
      * @see org.eclipse.ui.progress.IWorkbenchSiteProgressService#showBusyForFamily(Object)
      * @since 3.0
      */
     public void showBusy(boolean busy) {
         //By default do nothing
 }

     /**
      * {@inheritDoc}
      * <p>
      * It is considered bad practise to overload or extend this method.
      * Parts should call setPartName to change their part name.
      * </p>
      */
     public String getPartName() {
         return partName;
     }

     /**
      * Sets the name of this part. The name will be shown in the tab area for
      * the part. Clients should call this method instead of overriding getPartName.
      * Setting this to the empty string will cause a default part name to be used.
      *
      * <p>
      * setPartName and setContentDescription are intended to replace setTitle.
      * This may change a value that was previously set using setTitle.
      * </p>
      *
      * @param partName the part name, as it should be displayed in tabs.
      *
      * @since 3.0
      */
     protected void setPartName(String partName) {

         internalSetPartName(partName);

         setDefaultTitle();
     }

     void setDefaultTitle() {
         String description = getContentDescription();
         String name = getPartName();
         String newTitle = name;

         if (!Util.equals(description, "")) { //$NON-NLS-1$
 newTitle = MessageFormat
                     .format(
                             WorkbenchMessages.WorkbenchPart_AutoTitleFormat, new String [] { name, description });
         }

         setTitle(newTitle);
     }

     /**
      * {@inheritDoc}
      * <p>
      * It is considered bad practise to overload or extend this method.
      * Parts should call setContentDescription to change their content description.
      * </p>
      */
     public String getContentDescription() {
         return contentDescription;
     }

     /**
      * Sets the content description for this part. The content description is typically
      * a short string describing the current contents of the part. Setting this to the
      * empty string will cause a default content description to be used. Clients should
      * call this method instead of overriding getContentDescription(). For views, the
      * content description is shown (by default) in a line near the top of the view. For
      * editors, the content description is shown beside the part name when showing a
      * list of editors. If the editor is open on a file, this typically contains the path
      * to the input file, without the filename or trailing slash.
      *
      * <p>
      * This may overwrite a value that was previously set in setTitle
      * </p>
      *
      * @param description the content description
      *
      * @since 3.0
      */
     protected void setContentDescription(String description) {
         internalSetContentDescription(description);

         setDefaultTitle();
     }

     void internalSetContentDescription(String description) {
         Assert.isNotNull(description);

         //Do not send changes if they are the same
 if (Util.equals(contentDescription, description)) {
             return;
         }
         this.contentDescription = description;

         firePropertyChange(IWorkbenchPartConstants.PROP_CONTENT_DESCRIPTION);
     }

     void internalSetPartName(String partName) {
         partName = Util.safeString(partName);

         Assert.isNotNull(partName);

         //Do not send changes if they are the same
 if (Util.equals(this.partName, partName)) {
             return;
         }
         this.partName = partName;

         firePropertyChange(IWorkbenchPartConstants.PROP_PART_NAME);

     }
     

     /* (non-Javadoc)
      * @see org.eclipse.ui.part.IWorkbenchPartOrientation#getOrientation()
      */
     public int getOrientation(){
         //By default use the orientation in Window
 return Window.getDefaultOrientation();
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.IWorkbenchPart3#addPartPropertyListener(org.eclipse.jface.util.IPropertyChangeListener)
      */
     public void addPartPropertyListener(IPropertyChangeListener listener) {
         partChangeListeners.add(listener);
     }
     
     /* (non-Javadoc)
      * @see org.eclipse.ui.IWorkbenchPart3#removePartPropertyListener(org.eclipse.jface.util.IPropertyChangeListener)
      */
     public void removePartPropertyListener(IPropertyChangeListener listener) {
         partChangeListeners.remove(listener);
     }
     
     /**
      * @since 3.3
      */
     protected void firePartPropertyChanged(String key, String oldValue, String newValue) {
         final PropertyChangeEvent event = new PropertyChangeEvent(this, key, oldValue, newValue);
         Object [] l = partChangeListeners.getListeners();
         for (int i = 0; i < l.length; i++) {
             try {
                 ((IPropertyChangeListener)l[i]).propertyChange(event);
             } catch (RuntimeException e) {
                 WorkbenchPlugin.log(e);
             }
         }
     }
     
     private Map partProperties = new HashMap ();
     
     /* (non-Javadoc)
      * @see org.eclipse.ui.IWorkbenchPart3#setPartProperty(java.lang.String, java.lang.String)
      */
     public void setPartProperty(String key, String value) {
         String oldValue = (String ) partProperties.get(key);
         if (value==null) {
             partProperties.remove(key);
         } else {
             partProperties.put(key, value);
         }
         firePartPropertyChanged(key, oldValue, value);
     }
     
     /* (non-Javadoc)
      * @see org.eclipse.ui.IWorkbenchPart3#getPartProperty(java.lang.String)
      */
     public String getPartProperty(String key) {
         return (String )partProperties.get(key);
     }
     
     /* (non-Javadoc)
      * @see org.eclipse.ui.IWorkbenchPart3#getPartProperties()
      */
     public Map getPartProperties() {
         return Collections.unmodifiableMap(partProperties);
     }
 }

